#include "cMsg.h"

#include <Poco/DOM/DOMParser.h>
#include <Poco/DOM/NodeFilter.h>
#include <Poco/DOM/NamedNodeMap.h>
#include <Poco/DOM/AutoPtr.h>
#include "client/Client.h"
#include "misc/Debug.h"
#include "cRingRequest.h"
#include "cAnnounce.h"
#include "cDiscovery.h"
#include "cRingReply.h"
#include "cRingDeny.h"
#include "cRingDisconnect.h"
#include "cAck.h"
#include "cKeepAlive.h"
#include "cExecute.h"
#include "cData.h"
#include "cPut.h"
#include "cGet.h"
/*********************************************************/
using Poco::XML::XMLString;
using Poco::XML::DOMParser;
using Poco::XML::Document;
using Poco::XML::Node;
using Poco::XML::NodeIterator;
using Poco::XML::NodeFilter;
using Poco::XML::NamedNodeMap;
using Poco::XML::AutoPtr;
/*********************************************************/
cMsg* cMsg::deserialize(const std::string& xml)
{
	DOMParser 		parser;		// Parser that will parse the xml strings
	std::string		type;		// The type string of the job
	unsigned long 		id;		// Id of the message	

	AutoPtr<Document> pDoc = parser.parseString( xml );	// Parse the string into memory
	NodeIterator it(pDoc, NodeFilter::SHOW_ELEMENT);	// Node iterator to access the nodes
	Node* pNode = it.nextNode();				// Fetch the root node from the iterator

	// First node should be the root node, which is in our case "GS"
	if (( !pNode ) || ( pNode->nodeName() != "GS" )) {
		throw (std::logic_error("Attempt to deserialize an invalid packet! Invalid root node found or no root node present!"));
	} else {
		if ( pNode->hasAttributes() ) {
			NamedNodeMap *nnm = pNode->attributes();
			id = atoi(nnm->getNamedItem("id")->nodeValue().c_str());
			nnm->release();
		} else {
			throw ( std::logic_error("No id attribute found in the root node, invalid packet!"));
		}
	}
		
	// Get the next node, this should be the job node, with an attribute specifying the type of job
	pNode = it.nextNode();
	cMsg* msg = 0;
	if (( pNode ) && ( pNode->nodeName() == "RingRequest" )) {
		msg = new cRingRequest;
	} else if (( pNode ) && ( pNode->nodeName() == "Announce" )) {
		msg = new cAnnounce;
	} else if (( pNode ) && ( pNode->nodeName() == "Discovery" )) {
		msg = new cDiscovery;
	} else if (( pNode ) && ( pNode->nodeName() == "RingReply" )) {
		msg = new cRingReply;
	} else if (( pNode ) && ( pNode->nodeName() == "RingDeny" )) {
		msg = new cRingDeny;
	} else if (( pNode ) && ( pNode->nodeName() == "RingDisconnect" )) {
		msg = new cRingDisconnect;
	} else if (( pNode ) && ( pNode->nodeName() == "ACK" )) {
		msg = new cAck;
	} else if (( pNode ) && ( pNode->nodeName() == "KeepAlive" )) {
		msg = new cKeepAlive;
	} else if (( pNode ) && ( pNode->nodeName() == "Execute" )) {
		msg = new cExecute;
	} else if (( pNode ) && ( pNode->nodeName() == "Data" )) {
		msg = new cData;
	} else if (( pNode ) && ( pNode->nodeName() == "Put" )) {
		msg = new cPut;
	} else if (( pNode ) && ( pNode->nodeName() == "Get" )) {
		msg = new cGet;
	} else {
		throw (std::logic_error("Unknown packet contents, or incorrect packet data order!"));
	}

	msg->deserialize(it);
	if ( msg ) {
		msg->setID(id);
	}

	return msg;
}
/*********************************************************/
void cMsg::ack() const
{
	Client& c = Client::Instance();

	cMsg* ack = getAck();
	c.mutex.lock();
	c.net->sendTo(ack->serialize(), ack->getSenderAddr().toString());
	c.mutex.unlock();	
	delete( ack );
}
/*********************************************************/
cMsg* cMsg::getAck() const
{
	cMsg* ack = new cAck;
	ack->setSenderAddr(addr);
	ack->setID(id);
	return ack;
}
/*********************************************************/
void cMsg::setID(const unsigned long id)
{
	cMsg::id = id;
}
/*********************************************************/
unsigned long cMsg::getID() const
{
	return id;
}
/*********************************************************/
void cMsg::setSenderAddr(const Poco::Net::SocketAddress& addr)
{
	cMsg::addr = addr;
}
/*********************************************************/
Poco::Net::SocketAddress cMsg::getSenderAddr() const
{
	return cMsg::addr;
}
/*********************************************************/
